Technical Analysis Of Intel¶
Purpose¶
This phase of the project focuses on conducting an in-depth exploratory data analysis (EDA) of the selected stock. The goal is to extract valuable insights and explore key statistics that will lay the foundation for building a robust stock market forecasting system capable of providing actionable recommendationsāBuy, Sell, or Hold.
1.0 Load Data and Calculate Key Statistics¶
Potential stocks of interest¶
- INTC
- AAPL
- INTC
- MLTX
- TSLA
- HON
# Importing Libraries and Data
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import altair as alt
import mplfinance as mpf
import plotly.graph_objects as go
company_df = pd.read_csv('../data/sp500_companies.csv')
stock_df = pd.read_csv('../data/sp500_stocks.csv')
# Create new columns with Moving Averages and Standard Deviations
stock_df['Date'] = pd.to_datetime(stock_df['Date'])
stock_df['MA_10'] = stock_df.groupby('Symbol')['Close'].rolling(window=10).mean().reset_index(level=0, drop=True)
stock_df['MA_20'] = stock_df.groupby('Symbol')['Close'].rolling(window=20).mean().reset_index(level=0, drop=True)
stock_df['MA_50'] = stock_df.groupby('Symbol')['Close'].rolling(window=50).mean().reset_index(level=0, drop=True)
stock_df['MA_200'] = stock_df.groupby('Symbol')['Close'].rolling(window=200).mean().reset_index(level=0, drop=True)
stock_df['std_10'] = stock_df.groupby('Symbol')['Close'].rolling(window=10).std().reset_index(level=0, drop=True)
stock_df['std_20'] = stock_df.groupby('Symbol')['Close'].rolling(window=20).std().reset_index(level=0, drop=True)
stock_df['std_50'] = stock_df.groupby('Symbol')['Close'].rolling(window=50).std().reset_index(level=0, drop=True)
stock_df['std_200'] = stock_df.groupby('Symbol')['Close'].rolling(window=200).std().reset_index(level=0, drop=True)
# Create new columns with Bollinger Bands for each Moving Average
stock_df['upper_band_10'] = stock_df['MA_10'] + (stock_df['std_10'] * 2)
stock_df['lower_band_10'] = stock_df['MA_10'] - (stock_df['std_10'] * 2)
stock_df['upper_band_20'] = stock_df['MA_20'] + (stock_df['std_20'] * 2)
stock_df['lower_band_20'] = stock_df['MA_20'] - (stock_df['std_20'] * 2)
stock_df['upper_band_50'] = stock_df['MA_50'] + (stock_df['std_50'] * 2)
stock_df['lower_band_50'] = stock_df['MA_50'] - (stock_df['std_50'] * 2)
stock_df['upper_band_200'] = stock_df['MA_200'] + (stock_df['std_200'] * 2)
stock_df['lower_band_200'] = stock_df['MA_200'] - (stock_df['std_200'] * 2)
# Create new columns Indicating Golden Cross and Death Cross
stock_df['Golden_Cross_Short'] = np.where((stock_df['MA_10'] > stock_df['MA_20']) & (stock_df['MA_10'].shift(1) <= stock_df['MA_20'].shift(1)), 1, 0)
stock_df['Golden_Cross_Medium'] = np.where((stock_df['MA_20'] > stock_df['MA_50']) & (stock_df['MA_20'].shift(1) <= stock_df['MA_50'].shift(1)), 1, 0)
stock_df['Golden_Cross_Long'] = np.where((stock_df['MA_50'] > stock_df['MA_200']) & (stock_df['MA_50'].shift(1) <= stock_df['MA_200'].shift(1)), 1, 0)
stock_df['Death_Cross_Short'] = np.where((stock_df['MA_10'] < stock_df['MA_20']) & (stock_df['MA_10'].shift(1) >= stock_df['MA_20'].shift(1)), 1, 0)
stock_df['Death_Cross_Medium'] = np.where((stock_df['MA_20'] < stock_df['MA_50']) & (stock_df['MA_20'].shift(1) >= stock_df['MA_50'].shift(1)), 1, 0)
stock_df['Death_Cross_Long'] = np.where((stock_df['MA_50'] < stock_df['MA_200']) & (stock_df['MA_50'].shift(1) >= stock_df['MA_200'].shift(1)), 1, 0)
# Create new columns for MACD, Signal Line and MACD Histogram
def calculate_macd(df, short_window=12, long_window=26, signal_window=9):
# Calculate the short-term EMA
df['EMA_short'] = df['Close'].ewm(span=short_window, adjust=False).mean()
# Calculate the long-term EMA
df['EMA_long'] = df['Close'].ewm(span=long_window, adjust=False).mean()
# Calculate the MACD line
df['MACD'] = df['EMA_short'] - df['EMA_long']
# Calculate the Signal line
df['Signal'] = df['MACD'].ewm(span=signal_window, adjust=False).mean()
# Calculate the MACD histogram
df['MACD_Hist'] = df['MACD'] - df['Signal']
return df
stock_df = calculate_macd(stock_df)
# Create new columns for Average True Range (ATR) and True Range (TR)
stock_df['Previous_Close'] = stock_df['Close'].shift(1)
# True Range, Shows the volatility of the stock
stock_df['TR'] = stock_df.apply(
lambda row: max(
row['High'] - row['Low'], # High - Low
abs(row['High'] - row['Previous_Close']), # |High - Previous Close|
abs(row['Low'] - row['Previous_Close']) # |Low - Previous Close|
), axis=1
)
# Average True Range, Shows the average volatility of the stock
stock_df['ATR'] = stock_df['TR'].rolling(window=10).mean()
# Create new columns for Relative Strength Index (RSI)
def calculate_rsi(df, window=10):
# Calculate daily price changes
delta = df['Close'].diff()
# Separate gains and losses
gain = delta.where(delta > 0, 0)
loss = -delta.where(delta < 0, 0)
# Calculate the average gain and average loss
avg_gain = gain.rolling(window=window, min_periods=1).mean()
avg_loss = loss.rolling(window=window, min_periods=1).mean()
# Calculate the Relative Strength (RS)
rs = avg_gain / avg_loss
# Calculate the RSI
rsi = 100 - (100 / (1 + rs))
return rsi
# Add RSI column to the DataFrame
stock_df['RSI_10_Day'] = calculate_rsi(stock_df)
# Create new columns for 10 Day Rate of Change (ROC)
stock_df['10_Day_ROC'] = ((stock_df['Close'] - stock_df['Close'].shift(10)) / stock_df['Close'].shift(10)) * 100
# Create new columns for 10,20,50 day resistance and support levels
stock_df['Resistance_10_Day'] = stock_df['Close'].rolling(window=10).max()
stock_df['Support_10_Day'] = stock_df['Close'].rolling(window=10).min()
stock_df['Resistance_20_Day'] = stock_df['Close'].rolling(window=20).max()
stock_df['Support_20_Day'] = stock_df['Close'].rolling(window=20).min()
stock_df['Resistance_50_Day'] = stock_df['Close'].rolling(window=50).max()
stock_df['Support_50_Day'] = stock_df['Close'].rolling(window=50).min()
# Create new columns for 10,20,50 day Volume Indicators
stock_df['Volume_MA_10'] = stock_df['Volume'].rolling(window=10).mean()
stock_df['Volume_MA_20'] = stock_df['Volume'].rolling(window=20).mean()
stock_df['Volume_MA_50'] = stock_df['Volume'].rolling(window=50).mean()
# Create new columns for On Balance Volume (OBV)
def create_OBV(df):
df['OBV'] = 0
for i in range(1, len(df)):
if df['Close'].iloc[i] > df['Close'].iloc[i - 1]:
df.loc[df.index[i], 'OBV'] = df['OBV'].iloc[i - 1] + df['Volume'].iloc[i]
elif df['Close'].iloc[i] < df['Close'].iloc[i - 1]:
df.loc[df.index[i], 'OBV'] = df['OBV'].iloc[i - 1] - df['Volume'].iloc[i]
else:
df.loc[df.index[i], 'OBV'] = df['OBV'].iloc[i - 1]
return df
# stock_df = create_OBV(stock_df)
Preview Data with Additional Columns¶
# Preview Data
stock_df['Z-score'] = (stock_df['Close'] - stock_df['Close'].mean()) / stock_df['Close'].std()
stock_df['Daily Return'] = stock_df.groupby('Symbol')['Close'].pct_change(fill_method=None).reset_index(level=0, drop=True)
company_df.fillna(0, inplace=True)
stock_df.fillna(0, inplace=True)
stock_df
| Date | Symbol | Adj Close | Close | High | Low | Open | Volume | MA_10 | MA_20 | ... | Support_10_Day | Resistance_20_Day | Support_20_Day | Resistance_50_Day | Support_50_Day | Volume_MA_10 | Volume_MA_20 | Volume_MA_50 | Z-score | Daily Return | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2010-01-04 | A | 20.434929 | 22.389128 | 22.625179 | 22.267525 | 22.453505 | 3815561.0 | 0.000000 | 0.00000 | ... | 0.000 | 0.000000 | 0.000 | 0.000000 | 0.000 | 0.0 | 0.00 | 0.00 | -0.384398 | 0.000000 |
| 1 | 2010-01-05 | A | 20.212959 | 22.145924 | 22.331903 | 22.002861 | 22.324751 | 4186031.0 | 0.000000 | 0.00000 | ... | 0.000 | 0.000000 | 0.000 | 0.000000 | 0.000 | 0.0 | 0.00 | 0.00 | -0.385545 | -0.010863 |
| 2 | 2010-01-06 | A | 20.141132 | 22.067240 | 22.174536 | 22.002861 | 22.067240 | 3243779.0 | 0.000000 | 0.00000 | ... | 0.000 | 0.000000 | 0.000 | 0.000000 | 0.000 | 0.0 | 0.00 | 0.00 | -0.385915 | -0.003553 |
| 3 | 2010-01-07 | A | 20.115025 | 22.038628 | 22.045780 | 21.816881 | 22.017166 | 3095172.0 | 0.000000 | 0.00000 | ... | 0.000 | 0.000000 | 0.000 | 0.000000 | 0.000 | 0.0 | 0.00 | 0.00 | -0.386050 | -0.001297 |
| 4 | 2010-01-08 | A | 20.108498 | 22.031473 | 22.067240 | 21.745352 | 21.917025 | 3733918.0 | 0.000000 | 0.00000 | ... | 0.000 | 0.000000 | 0.000 | 0.000000 | 0.000 | 0.0 | 0.00 | 0.00 | -0.386084 | -0.000325 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 1875709 | 2024-10-28 | LYV | 118.430000 | 118.430000 | 119.389999 | 116.904999 | 117.160004 | 1786063.0 | 116.653001 | 115.03400 | ... | 0.389 | 233.399994 | 0.389 | 749.119995 | 0.389 | 18070329.9 | 16995342.65 | 12071518.84 | 0.068235 | 0.000000 |
| 1875710 | 2024-10-28 | INTC | 22.920000 | 22.920000 | 23.270000 | 22.559999 | 22.684999 | 38933999.0 | 22.627160 | 22.78258 | ... | 0.389 | 233.399994 | 0.389 | 749.119995 | 0.389 | 18490356.5 | 18852739.45 | 12847144.68 | -0.381896 | 0.000000 |
| 1875711 | 2024-10-28 | DNMR | 0.389000 | 0.389000 | 0.395600 | 0.370000 | 0.403000 | 1270538.0 | 0.000000 | 0.00000 | ... | 0.389 | 233.399994 | 0.389 | 749.119995 | 0.389 | 17647780.5 | 17179579.70 | 12845380.04 | -0.488083 | 0.000000 |
| 1875712 | 2024-10-28 | SPCE | 7.740000 | 7.740000 | 7.870000 | 7.142600 | 7.210000 | 2533542.0 | 0.000000 | 0.00000 | ... | 0.389 | 233.399994 | 0.389 | 749.119995 | 0.389 | 15497806.0 | 16821441.90 | 12892494.20 | -0.453439 | 0.000000 |
| 1875713 | 2024-10-29 | INTC | 22.705000 | 22.705000 | 23.139999 | 22.410000 | 22.870001 | 43573446.0 | 22.620660 | 22.78833 | ... | 0.389 | 233.399994 | 0.389 | 749.119995 | 0.389 | 19676544.3 | 17798449.85 | 13718152.06 | -0.382910 | -0.009380 |
1875714 rows Ć 51 columns
Column Descriptions¶
- Date: The date of the stock data entry.
- Symbol: The ticker symbol representing the stock.
- Adj Close: The adjusted closing price of the stock, accounting for corporate actions like dividends and stock splits.
- Close: The closing price of the stock on the given date.
- High: The highest price at which the stock traded during the day.
- Low: The lowest price at which the stock traded during the day.
- Open: The opening price of the stock on the given date.
- Volume: The number of shares traded during the day.
- MA_10: The 10-day moving average of the stock's closing price.
- MA_20: The 20-day moving average of the stock's closing price.
- MA_50: The 50-day moving average of the stock's closing price.
- MA_200: The 200-day moving average of the stock's closing price.
- std_10: The standard deviation of the stock's closing price over the past 10 days.
- std_20: The standard deviation of the stock's closing price over the past 20 days.
- std_50: The standard deviation of the stock's closing price over the past 50 days.
- std_200: The standard deviation of the stock's closing price over the past 200 days.
- upper_band_10: The upper Bollinger Band based on the 10-day moving average and standard deviation.
- lower_band_10: The lower Bollinger Band based on the 10-day moving average and standard deviation.
- upper_band_20: The upper Bollinger Band based on the 20-day moving average and standard deviation.
- lower_band_20: The lower Bollinger Band based on the 20-day moving average and standard deviation.
- upper_band_50: The upper Bollinger Band based on the 50-day moving average and standard deviation.
- lower_band_50: The lower Bollinger Band based on the 50-day moving average and standard deviation.
- upper_band_200: The upper Bollinger Band based on the 200-day moving average and standard deviation.
- lower_band_200: The lower Bollinger Band based on the 200-day moving average and standard deviation.
- Golden_Cross_Short: Indicator for a short-term golden cross, where the 10-day moving average crosses above the 20-day moving average.
- Golden_Cross_Medium: Indicator for a medium-term golden cross, where the 20-day moving average crosses above the 50-day moving average.
- Golden_Cross_Long: Indicator for a long-term golden cross, where the 50-day moving average crosses above the 200-day moving average.
- Death_Cross_Short: Indicator for a short-term death cross, where the 10-day moving average crosses below the 20-day moving average.
- Death_Cross_Medium: Indicator for a medium-term death cross, where the 20-day moving average crosses below the 50-day moving average.
- Death_Cross_Long: Indicator for a long-term death cross, where the 50-day moving average crosses below the 200-day moving average.
- EMA_short: The short-term Exponential Moving Average (EMA) of the stock's closing price.
- EMA_long: The long-term Exponential Moving Average (EMA) of the stock's closing price.
- MACD: The Moving Average Convergence Divergence, calculated as the difference between the short-term EMA and the long-term EMA.
- Signal: The signal line for the MACD, which is the EMA of the MACD line.
- MACD_Hist: The MACD histogram, calculated as the difference between the MACD line and the signal line.
- Previous_Close: The closing price of the stock on the previous trading day.
- TR: The True Range, a measure of the stock's volatility.
- ATR: The Average True Range, the moving average of the True Range, indicating the average volatility.
- RSI_10_Day: The 10-day Relative Strength Index, a momentum oscillator that measures the speed and change of price movements.
- 10_Day_ROC: The 10-day Rate of Change, showing the percentage change in the stock's closing price over the past 10 days.
- Z-score: The Z-score of the stock's closing price, indicating how many standard deviations the closing price is from the mean.
- Daily Return: The daily return of the stock, calculated as the percentage change in the closing price from the previous day.
alt.data_transformers.disable_max_rows()
def plot_closing_price(df, company,opacity=1):
filtered_df = df[df['Symbol'] == company]
chart = alt.Chart(filtered_df).mark_line(color='black', opacity=opacity).encode(
alt.X('Date:T', title='Date'),
alt.Y('Close:Q', title='Closing Price'),
alt.Tooltip(['Date:T', 'Close:Q', 'Volume:Q','RSI_10_Day']),
).properties(
title=f'{company} Closing Price',
width=800,
height=400
).interactive(
bind_y=False
)
return chart
plot_closing_price(stock_df, 'INTC')
There has been a strong upwards trend until around 2020 this is due to Intels strong presence in the tech field manufacturing computer chips. Strong downwards trends then began until 2024, this is due to the first reals competetors on the market outperforming intel.Another down trend starts around Q1 of 2024. Overall INTC is a historically strong stock but due to competition and the pandemic has since become volitile, will need to see them regain competitive edge before long term investments but short term can be money maker.
CandleStick Chart¶
def plot_candlestick(df, company,window:list = None,SR_window=10):
# Fileter data to specified stock and date range
filtered_df = df[df['Symbol'] == company]
filtered_df = filtered_df[filtered_df['Date'] >= window[0]]
filtered_df = filtered_df[filtered_df['Date'] <= window[1]]
filtered_df['Date'] = pd.to_datetime(filtered_df['Date'])
df = filtered_df
# Create the Candlesick Chart
candlestick = go.Candlestick(
x=df['Date'],
open=df['Open'],
high=df['High'],
low=df['Low'],
close=df['Close'],
name='Candlestick'
)
# Create the Volume Bar graph
volume = go.Bar(
x=df['Date'],
y=df['Volume'],
name='Volume',
marker_color='blue',
opacity=0.5,
yaxis='y2'
)
# Create the Support and Resistance Lines
support = go.Scatter(
x=df['Date'],
y=df[f'Support_{SR_window}_Day'],
mode='lines',
name=f'Support {SR_window} Day',
line=dict(color='green', width=1)
)
resistance = go.Scatter(
x=df['Date'],
y=df[f'Resistance_{SR_window}_Day'],
mode='lines',
name=f'Resistance {SR_window} Day',
line=dict(color='red', width=1)
)
# Create the Layout for the Chart (Title, Axis Labels, etc.)
layout = go.Layout(
title= f'{company} Candlestick Chart From {window[0]} to {window[1]}',
xaxis=dict(title='Date'),
yaxis=dict(title='Price', showgrid=True),
yaxis2=dict(title='Volume', overlaying='y', side='right', showgrid=False),
xaxis_rangeslider_visible=False,
hovermode='x unified', # Compare data points on hover
plot_bgcolor='white'
)
# Layer all the charts together into one figure
fig = go.Figure(
data=[candlestick, volume, support, resistance],
layout=layout
)
return fig
plot_candlestick(stock_df, 'INTC', window=['2024-06-01', '2024-10-01'],SR_window=20)
The candlestick comfirms much of what the closing price does but zooming in on the past 3 months we can see recent drop due to missing Q2 earning by .08%. Since then the stock has been pretty stagnat with few flucuations; mass hold possible breakout soon. Recent signs show possible growth specifically with the engulfing candle on September 20th. Stock price rising higher than 20 day resistance, not worrying due to recent price drop, volume indicates significance with this breakout. Support Shift??
def plot_moving_average(df, company, color, MA,term):
filtered_df = df[df['Symbol'] == company]
chart = alt.Chart(filtered_df).mark_line(color=color).encode(
alt.X('Date:T', title='Date'),
alt.Y(f'{MA}:Q', title='{MA}'),
alt.Tooltip([MA,'Date', 'Close:Q', 'Volume:Q', 'Death_Cross_Short:O', 'Golden_Cross_Short:O', 'Death_Cross_Long:O', 'Golden_Cross_Long:O'])
).properties(
title=f'{company} Moving Average {term}',
width=800,
height=400
).interactive(
bind_y=False
)
return chart
closing_price = plot_closing_price(stock_df, 'INTC', 0.5)
MA_10 = plot_moving_average(stock_df, 'INTC', 'green', 'MA_10','Short Term')
MA_20 = plot_moving_average(stock_df, 'INTC', 'blue', 'MA_20','Short Term')
MA_50 = plot_moving_average(stock_df, 'INTC', 'red', 'MA_50','Long Term')
MA_200 = plot_moving_average(stock_df, 'INTC', 'purple', 'MA_200','Long Term')
short_term_MA = alt.layer(MA_10, MA_20, closing_price)
medium_term_MA = alt.layer(MA_200, MA_50, closing_price)
MA_charts = alt.vconcat(short_term_MA, medium_term_MA)
MA_charts
The averages also align with previos charts with Short Term Golden Cross also occuring on September 20th, this is a sign buyers will be stepping in and possible gain in the short term. Long term the averages are down with the 200 day showing signs of rise but the 50 day showing signs of decline, the stock price is however about to move above the 50 day average indicating medium term stock rise. Death Cross on May 2nd yet to uncross, not looking good long term
Bollinger Bands¶
def plot_bollinger_bands(df, company, band):
# Filter data to specified stock and date range
df = df[df['Symbol'] == company]
window=['2023-01-01', '2024-10-01']
df = df[df['Date'] >= window[0]]
df = df[df['Date'] <= window[1]]
fig = go.Figure()
# Create the Close Price Line Chart
fig.add_trace(
go.Scatter(
x=df['Date'],
y=df['Close'],
mode='lines',
name='Close Price'
)
)
# Create the upper band
fig.add_trace(
go.Scatter(
x=df['Date'],
y=df[f'upper_band_{band}'],
mode='lines',
name='Upper Band',
line=dict(color='red', width=1)
)
)
# Create the lower band
fig.add_trace(
go.Scatter(
x=df['Date'],
y=df[f'lower_band_{band}'],
mode='lines',
fill='tonexty',
fillcolor='rgba(128, 128, 128, 0.2)',
name='Lower Band',
line=dict(color='red', width=1)
)
)
# Update layout
fig.update_layout(
title=f'Bollinger Bands for {band} Day Moving Average',
xaxis_title='Date',
yaxis_title='Price',
legend_title='Legend',
width=1000,
height=600
)
fig.show()
band_10 = plot_bollinger_bands(stock_df, 'INTC', 10)
band_20 = plot_bollinger_bands(stock_df, 'INTC', 20)
band_50 = plot_bollinger_bands(stock_df, 'INTC', 50)
# band_200 = plot_bollinger_bands(stock_df, 'INTC', 200)
The bollinger bands are all widening which indicates a volitile stock, to be expected with possible breakout pending.
Relative Strength Index¶
def plot_RSI(df, company,start):
filtered_df = df[df['Symbol'] == company]
filtered_df = filtered_df[filtered_df['Date'] >= start]
fig, axs = plt.subplots(2, 1, gridspec_kw={'height_ratios': [3, 1]}, figsize=(10, 6))
axs[0].set_title(f'{company} Closing Price')
axs[0].plot(filtered_df['Date'],filtered_df['Close'], color='black')
axs[1].axhline(y=70, color='red', linestyle='--')
axs[1].axhline(y=30, color='green', linestyle='--')
axs[1].plot(filtered_df['Date'],filtered_df['RSI_10_Day'], color='orange')
axs[1].set_title('RSI')
plt.show()
plot_RSI(stock_df, 'INTC', '2024-06-01')
The RSI indicates that the stock is currently overbought which is likely due to the recent bullish signal from the candlestick chart, this likely lead to an increace of investors. This is worrying due to the signal often leading to a downtrend as seen in july.
from plotly.subplots import make_subplots
def plot_MACD(df, company, start, stop):
# Filter the DataFrame for the specified company and date range
df = df[(df['Symbol'] == company)]
df = df[df['Date'] >= start]
df = df[df['Date'] <= stop]
# Create a Plotly figure with two subplots
fig = make_subplots(
rows=2,
cols=1,
shared_xaxes=True,
vertical_spacing=0.1,
subplot_titles=('Close Price', 'MACD')
)
# Add Close Price graph
fig.add_trace(go.Scatter(
x=df['Date'], y=df['Close'],
mode='lines',
name='Close Price'
), row=1, col=1)
# Add MACD line graph
fig.add_trace(go.Scatter(
x=df['Date'], y=df['MACD'],
mode='lines',
name='MACD',
line=dict(color='red')
), row=2, col=1)
# Add Signal line graph
fig.add_trace(go.Scatter(
x=df['Date'], y=df['Signal'],
mode='lines',
name='Signal',
line=dict(color='blue')
), row=2, col=1)
# Add MACD histogram
fig.add_trace(go.Bar(
x=df['Date'], y=df['MACD_Hist'],
name='MACD Histogram',
marker_color=['green' if x > 0 else 'red' for x in df['MACD_Hist']]
), row=2, col=1)
# Update layout
fig.update_layout(
title=f'MACD for {company}',
xaxis_title='Date',
yaxis_title='Price',
legend_title='Legend',
width=1000,
height=600
)
fig.show()
start = pd.to_datetime('01-01-2024')
stop = pd.to_datetime('09-29-2024')
MACD = plot_MACD(stock_df, 'INTC', start, stop)
The MACD indicates that the best time to buy wouldve been around the middle of September, currently bullish signal.